Multi-Tasking
Task: Eine Aufgabe die von der CPU abgearbeitet wird Batch-Ausführen: Führ die anstehenden Tasks nacheinander durch. Multi-Tasking: Führt die Prozesse gleichzeitig / nebeneinander aus
Scheduling
Kooperativ: Jeder Task entschieden, wann sie die Kontrolle an einen anderen Task abgibt. Präemptiv: Kontrollübergabe an den nächsten Task wird erzwungen Scheduler
- Unterbricht präemtiv
- entscheidet welche Tasks dran sind
- Round robin (im Kreis herum)
- Priority driven
Fork
Nach dem fork existiert der Kindprozess als Kopie des original Prozesses.
- Bisherige Variablen werden also exakt kopiert
- Somit sind auch offene Files dann „doppelt“ vorhanden. Also immer aufpassen
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#define PERROR_AND_EXIT(M) do { perror(M); exit(EXIT_FAILURE); } while(0)
int main()
{
// Erstelle neuen Child prozess
// setzt DANACH die childId
pid_t childId = fork();
if (childId == -1)
{
PERROR_AND_EXIT("fork");
}
if (childId > 0)
{
// ChildId ist gesetzt, also sind wir im Parent
printf("Parent: %d forked child %d\n", getpid(), childId);
int wstatus;
// Jetzt warten wir, bis der Prozess des Kindes
// fertig ist, 0 -> kein timeout also unendlich lange
pid_t wpid = waitpid(childId, &wstatus, 0);
printf("Child exited with status: %d \n", WEXITSTATUS(wstatus));
// jetzt beenden wir den Parent mit Success
exit(EXIT_SUCCESS);
}
else
{
// Da childId noch nicht gesetzt ist, zum Zeitpunkt des forks
// Wissen wir, dass wir im child sind
printf("Child: %d forked by parent %d\n", getpid(), getppid());
sleep(3);
exit(123);
}
}
// Parent erstellt neues Kind
// Kind wird ausgeführt, blockiert parent bis abgeschlossen (exit)
// Parent wird abgeschlossen (exit)
Exec
Ersetzt den Childprozess durch ein anders ausführbares Programm.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#define PERROR_AND_EXIT(M) do { perror(M); exit(EXIT_FAILURE); } while(0)
int main()
{
// Erstelle neuen Child prozess
// setzt DANACH die childId
pid_t childId = fork(); // Erstelle neues Kind
if (childId == -1)
{
PERROR_AND_EXIT("fork");
}
if (childId > 0)
{
// ChildId ist gesetzt, also sind wir im Parent
printf("Parent: %d forked child %d\n", getpid(), childId);
int wstatus;
// Jetzt warten wir, bis der Prozess des Kindes
// fertig ist, 0 -> kein timeout also unendlich lange
pid_t wpid = waitpid(childId, &wstatus, 0);
printf("Child exited with status: %d \n", WEXITSTATUS(wstatus));
// jetzt beenden wir den Parent mit Success
exit(EXIT_SUCCESS);
}
else
{
// Da childId noch nicht gesetzt ist, zum Zeitpunkt des forks
// Wissen wir, dass wir im child sind
// Wir definieren die Befehle einzel
// in diesem fall „ls -l“
static char *eargv[] = { "ls", "-l", NULL };
if (execv("/bin/ls", eargv) == -1)
{
PERROR_AND_EXIT("execv: /bin/ls");
}
// Das exec denn Prozess ersetzt, wird diese Zeile nie getroffen
}
}
System
- Spaltet einen Prozess ab fork())
- startet die System-Shell, führt in dieser Shell das angegebene Kommando aus
- Wartet blockierend auf das Terminieren des Prozesses (waitpid())
WEXITSTATUS
Extrahiert den Exitcode aus dem zurückgegebenen Status des system() Befehles
int ret = system("/bin/ls -l");
POPEN
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define PERROR_AND_EXIT(M) do { perror(M); exit(EXIT_FAILURE); } while(0)
const static int BUFSIZE = 100;
int main()
{
// 2 = error pipe in null schreiben, also entsorgen
FILE *df = popen("df -k --output=pcent . 2>/dev/null", "r");
if (!df) {
PERROR_AND_EXIT("popen: df -k .");
}
char line[BUFSIZE];
char *end = NULL;
long int used = -1;
while (fgets(line, BUFSIZE, df)) {
used = strtol(line, &end, 10);
if (end && end != line && *end == '%') {
break;
}
used = -1;
}
if (pclose(df)) {
PERROR_AND_EXIT("failed with pclose()");
}
if (used < 0 || used > 100) {
errno = ERANGE;
PERROR_AND_EXIT("df -k .");
}
char *msg
= used < 60 ? "Plenty of disk space (%d%% available) \n"
: used < 80 ? "Maybe some future disk space problems (%d%% available) \n"
: used < 90 ? "Need to clear out files (%d%% available) \n"
: "You may face soon some severe disk space problems (%d%% available) \n";
printf(msg, 100-used);
return EXIT_SUCCESS;
}
SO BAUEN
gcc -pthread t08/popen.c
Threads
Da das OS die Threads selber verwaltet, kann es sein, dass die Ausgabe auf der Konsole sich verändert. Wenn jetzt z.B. der Child Prozess eine höhere Priorität hat, dann ist es möglich, dass dieser VOR dem Main prozess endet.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#define PERROR_AND_EXIT(M) do { perror(M); exit(EXIT_FAILURE); } while(0)
// Definiere den worker thread, diese Funktion
// wird im thread später ausgeführt
void *worker(void *arg)
{
printf("worker\n");
sleep(3);
static int ret_value = 123;
return &ret_value;
}
int main()
{
pthread_t thread;
// erstelle neuen thread
// thread -> speichere diesen in die thread adresse
// NULL -> pthread_attr_t: erlaubt also einige Attribute zu setzen
// worker -> welche Funktion soll ausgefüht werden
// NULL -> argument zur Funktion, da kann auch alles mögliche drin stehen
int status = pthread_create(&thread, NULL, worker, NULL);
if (status != 0)
{
// Thread konnte nicht erstellt werden
exit (status);
}
printf("main\n");
static void *retVal;
status = pthread_join(thread, &retVal);
if (status != 0)
{
// Thread konnte nicht beigetreten werden,
// es ist etwas schief gelaufen
exit (status);
}
printf("worker retval = %d\n", *((int*)retVal));
exit (EXIT_SUCCESS);
}
DU SO BAUEN
gcc -pthread t08/threads.c
Loslassen eines Threads (Detach)
Funktion: pthread_detach() Gibt an, dass sobald der Thread beendet wird, die Ressourcen freigegeben werden. Normalerweise passiert dies erst beim pthread_join.
-> Es darf NICHT mit pthread_join auf den Prozess gewartet werden, da dieser bereits weg sein kann.
Terminierung eines Threads
- return: Standardmässig, der Rückgabewert wird bei pthread_join zurückgegeben.
- pthread_exit: so ist es möglich, den thread zu beenden. Der Rückgabewert wird bei pthread_join gelesen.
- exit beendet den übergeordneten Prozess
- pthread_cancel: Wird verwendet um den Prozess zu beenden.